package com.alibaba.citrus.cr.mn.order.center.facade.repository.impl;

import cn.hutool.core.date.StopWatch;
import com.alibaba.citrus.cr.b2b.trade.order.facade.common.SetOrderTag;
import com.alibaba.citrus.cr.common.annotation.EpochTransactional;
import com.alibaba.citrus.cr.common.annotation.RepositoryInvoker;
import com.alibaba.citrus.cr.common.exception.FunctionException;
import com.alibaba.citrus.cr.mn.order.center.facade.function.dataobject.AtomOrderDO;
import com.alibaba.citrus.cr.mn.order.center.facade.repository.AtomOrderRepository;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.lattice2.epoch.db.service.CustomSequenceAccessor;
import com.epoch.app.crb2btradecenter.domain.order.dto.UpdateOrderStatusRequest;
import com.epoch.app.crb2btradecenter.domain.order.model.Order;
import com.epoch.app.crb2btradecenter.domain.order.service.OrderService;
import com.epoch.app.crb2btradecenter.domain.orderline.dto.UpdateOrderLineResponse;
import com.epoch.app.crb2btradecenter.domain.orderline.model.OrderLine;
import com.epoch.app.crb2btradecenter.domain.orderline.service.OrderLineService;
import com.epoch.app.crb2btradecenter.enums.OrderStatus;
import com.epoch.app.mnordercenter.model.dto.SalesOrderAtomCreateResponse;
import com.epoch.app.mnordercenter.orderbaserequest.OrderLineAtomCreateResponse;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author zhangxiaorui
 * @ClassName AtomOrderRepositoryImpl
 * @description: TODO
 * @date 2023/04/25 20:14
 * @version: 1.0
 */
@Component
public class AtomOrderRepositoryImpl implements AtomOrderRepository {
    private static final Log log = Log.getLogger(AtomOrderRepositoryImpl.class);

    @Resource
    private CustomSequenceAccessor customSequenceAccessor;

    @Resource
    private OrderService orderService;

    @Resource
    private OrderLineService orderLineService;

    @Override
    @RepositoryInvoker
    public SalesOrderAtomCreateResponse saveOrder(AtomOrderDO atomOrderDO) {
        Order mainOrder = assembleSaveOrder(atomOrderDO);
        if (Objects.nonNull(atomOrderDO.getFactoryBusinessOrderDO())) {
            Order mainGroupOrder = assembleSaveOrder(atomOrderDO.getFactoryBusinessOrderDO());
            //B-b设置关联单号
            mainOrder.setRelationNo(mainGroupOrder.getOrderBizId());
            //B-b设置关联单行号
            atomOrderDO.getOrderLines().forEach(it -> it.setRelationLineNo(it.getSerialNumber()));
            //F-B设置关联单号
            mainGroupOrder.setRelationNo(mainOrder.getOrderBizId());
            //B-b设置关联单行号
            atomOrderDO.getFactoryBusinessOrderDO().getOrderLines().forEach(it -> it.setRelationLineNo(it.getSerialNumber()));
            doSaveOrder(mainGroupOrder, atomOrderDO.getFactoryBusinessOrderDO());
        }
        return doSaveOrder(mainOrder, atomOrderDO);
    }

    private SalesOrderAtomCreateResponse doSaveOrder(Order mainOrder ,AtomOrderDO atomOrderDO){
        try {
            log.info("AtomOrderRepositoryImpl#saveOrder mainOrder={}", mainOrder);
            String orderId = orderService.createOrder(mainOrder).getLastInsertId();
            if (StringUtils.isBlank(orderId)) {
                log.error("AtomOrderRepositoryImpl#saveOrder createOrder fail mainOrder={}", JSONObject.toJSONString(mainOrder));
                return failSaveOrder(atomOrderDO);
            }
            // 设置主单ID
            mainOrder.setId(Long.parseLong(orderId));
        } catch (Exception e) {
            log.error("AtomOrderRepositoryImpl#saveOrder error", e);
            return failSaveOrder(atomOrderDO);
        }

        SalesOrderAtomCreateResponse mainOrderResponse = successSaveOrder(atomOrderDO);
        for (OrderLine line : atomOrderDO.getOrderLines()) {
            line.setMainOrderId(String.valueOf(mainOrder.getId()));
            line.setMainOrderBizId(mainOrder.getOrderBizId());
            line.setOrderLineTag(Optional.ofNullable(line.getOrderLineTag()).orElse(SetOrderTag.NORMAL));
            line.setStatus(Optional.ofNullable(line.getStatus()).orElse(OrderStatus.BEFORE_SUBMIT.getCode()));
            line.setGmtCreate(new Date());
            line.setGmtModified(new Date());
            line.setSyncVersion(0);

            try {
                log.info("AtomOrderRepositoryImpl#saveOrder line={}", line);
                String orderLineId = orderLineService.createOrderLine(line).getLastInsertId();
                if (StringUtils.isNotBlank(orderLineId)) {
                    // 设置明细单ID
                    line.setId(Long.parseLong(orderLineId));
                    // 记录成功行信息
                    String scItemId = parseMoneyFromFeatures(line, "productCode", line.getScItemId());
                    addSuccessDetailsResponse(mainOrderResponse, line.getSerialNumber(), scItemId, line.getSourceLineNum());
                    continue;
                }
                log.error("AtomOrderRepositoryImpl#createOrderLine createOrderLine fail line={}", JSONObject.toJSONString(line));
                // 记录失败行信息
                String scItemId = parseMoneyFromFeatures(line, "productCode", line.getScItemId());
                // 记录失败行信息
                addFailDetailsResponse(mainOrderResponse, line.getSourceLineNum(), scItemId);
            } catch (Exception e) {
                log.error("AtomOrderRepositoryImpl#createOrderLine error", e);
                // 记录失败行信息
                String scItemId = parseMoneyFromFeatures(line, "productCode", line.getScItemId());
                // 记录失败行信息
                addFailDetailsResponse(mainOrderResponse, line.getSourceLineNum(), scItemId);
            }
        }

        return mainOrderResponse;
    }

    /**
     * @param orderLine
     * @param key
     * @param defaultVal
     * @return
     */
    private static String parseMoneyFromFeatures(OrderLine orderLine, String key, String defaultVal) {
        Map<String, String> featuresMap = JSONObject.parseObject(orderLine.getFeatures(), new TypeReference<Map<String, String>>() {
        });
        if (MapUtils.isEmpty(featuresMap)) {
            return defaultVal;
        }
        return featuresMap.getOrDefault(key, defaultVal);
    }

    @Override
    @RepositoryInvoker
    @EpochTransactional(appCode = "mn_order_center", dataSourceCode = "cr_ots", dataSourceType = "app")
    public void saveOrder2(AtomOrderDO atomOrder, SalesOrderAtomCreateResponse response) {
        try {
            Order mainOrder = assembleSaveOrder(atomOrder);
            String orderId = orderService.createOrder(mainOrder).getLastInsertId();
            log.info("主单保存结果 mainOrderId={}", orderId);
            // 校验主单ID，异常则返回且进行事务回滚
            checkOrderErrAndAddFailMsg(StringUtils.isBlank(orderId), atomOrder, response);

            // 设置主单ID
            mainOrder.setId(Long.parseLong(orderId));
            // 创建来源单-销售订单映射【主单】
            setSuccessOrderResponse(response, mainOrder);

            for (OrderLine orderLine : atomOrder.getOrderLines()) {
                orderLine.setMainOrderBizId(mainOrder.getOrderBizId());
                orderLine.setMainOrderId(orderId);
                orderLine.setOrderLineTag(SetOrderTag.NORMAL);
                orderLine.setGmtCreate(new Date());
                orderLine.setGmtModified(new Date());
                orderLine.setSyncVersion(0);
                String orderLineId = orderLineService.createOrderLine(orderLine).getLastInsertId();
                // 校验主单ID，异常则返回且进行事务回滚
                checkOrderLineErrAndAddFailMsg(StringUtils.isBlank(orderLineId), orderLine, response);

                // 设置明细单ID
                orderLine.setId(Long.parseLong(orderLineId));
                // 创建来源单-销售订单映射【主单】
                addSuccessDetailsResponse(response, orderLine);
            }
        } catch (FunctionException fex) {
            log.info("业务主动校验异常已经进行response组装，此处不再进行异常处理");
        } catch (Throwable e) {
            log.error("非业务主动校验异常，需根据场景处理，事务回滚", e);
            throw e;
        }
    }

    @Override
    public void updateOrderStatus(AtomOrderDO atomOrder) {
        log.info("AtomOrderRepositoryImpl#updateOrder atomOrder={}", JSONObject.toJSONString(atomOrder));
        StopWatch stopWatch = new StopWatch("订单中心原子提交");

        stopWatch.start("updateMainOrder");
        updateMainOrder(atomOrder.getOrder());
        stopWatch.stop();

        stopWatch.start("updateMainOrderLine");
        updateMainOrderLine(atomOrder.getOrderLines());
        stopWatch.stop();

        log.info("AtomOrderRepositoryImpl#updateOrder stopWatch.getTotalTimeSeconds()={}", stopWatch.getTotalTimeSeconds());
        log.info("AtomOrderRepositoryImpl#updateOrder stopWatch.prettyPrint()={}", stopWatch.prettyPrint(TimeUnit.MILLISECONDS));
    }

    private void updateMainOrderLine(List<OrderLine> orderLines) {
        if (CollectionUtils.isEmpty(orderLines)) {
            return;
        }
        try {
            // List<Long> toUpdateOrderLineIds = new ArrayList<>();
            for (OrderLine orderLine : orderLines) {
                log.info("AtomOrderRepositoryImpl#updateMainOrderLine orderLine:{}", JSONObject.toJSONString(orderLine));
                if (Objects.isNull(orderLine.getId())) {
                    // todo 改为批量创建
                    orderLineService.createOrderLine(orderLine);
                    continue;
                } else {
                    OrderLine orderLineNew = new OrderLine();
                    orderLineNew.setId(orderLine.getId());
                    orderLineNew.setMainId(orderLine.getMainId());
                    orderLineNew.setReceiveWarehouseOutCode(orderLine.getReceiveWarehouseOutCode());
                    orderLineNew.setReceiveWarehouseCode(orderLine.getReceiveWarehouseCode());
                    orderLineNew.setReceiveWarehouseName(orderLine.getReceiveWarehouseName());
                    orderLineNew.setReceiveFactoryCode(orderLine.getReceiveFactoryCode());
                    orderLineNew.setReceiveFactoryName(orderLine.getReceiveFactoryName());
                    orderLineNew.setReceiveStockCode(orderLine.getReceiveStockCode());
                    orderLineNew.setReceiveStockName(orderLine.getReceiveStockName());
                    orderLineNew.setStatus(orderLine.getStatus());
                    UpdateOrderLineResponse updateOrderLine = orderLineService.updateOrderLine(orderLine);
                    if (updateOrderLine.getCount() != 1) {
                        log.error("AtomOrderRepositoryImpl#updateMainOrderLine orderLine:{}; updateOrderLine:{}", JSONObject.toJSONString(orderLine), JSONObject.toJSONString(updateOrderLine));
                    }
                }
                // toUpdateOrderLineIds.add(orderLine.getId());
            }
            // if (CollectionUtils.isEmpty(toUpdateOrderLineIds)) {
            //     return;
            // }
            // BatchUpdateStatusRequest batchUpdateStatusRequest = new BatchUpdateStatusRequest();
            // batchUpdateStatusRequest.setOrderLineIds(toUpdateOrderLineIds);
            // batchUpdateStatusRequest.setStatus(orderLines.get(0).getStatus());
            // BatchUpdateStatusResponse batchUpdateStatusResponse = orderLineService.batchUpdateStatus(batchUpdateStatusRequest);
            // log.info("AtomOrderRepositoryImpl#updateMainOrderLine batchUpdateStatusRequest={}", batchUpdateStatusRequest);
            // if (batchUpdateStatusResponse.getCount() != toUpdateOrderLineIds.size()) {
            //     log.error("AtomOrderRepositoryImpl#updateMainOrderLine batchUpdateStatusResponse={}", batchUpdateStatusResponse);
            // }
        } catch (Exception e) {
            log.error("AtomOrderRepositoryImpl#updateMainOrderLine error", e);
        }
    }

    private void updateMainOrder(Order order) {
        UpdateOrderStatusRequest updateOrderStatusRequest = new UpdateOrderStatusRequest();
        updateOrderStatusRequest.setOrderBizIds(Lists.newArrayList(order.getOrderBizId()));
        updateOrderStatusRequest.setStatus(order.getStatus());
        updateOrderStatusRequest.setModifierCode(order.getModifierCode());
        updateOrderStatusRequest.setModifierName(order.getModifierName2());
        try {
            orderService.updateOrderStatus(updateOrderStatusRequest);
        } catch (Exception e) {
            log.error("AtomOrderRepositoryImpl#updateMainOrder updateOrderStatus error", e);
        }
    }

    private static void checkOrderErrAndAddFailMsg(boolean checkTrue, AtomOrderDO atomOrder, SalesOrderAtomCreateResponse response) {
        if (checkTrue) {
            // 追加异常信息返回
            response.setSourceOrderNo(atomOrder.getOrder().getSourceOrderNo());
            response.setErrorCode("OC-01-001-01-16-007");
            response.setMessage("销售订单批量创建整单失败");
            // DB事务回滚
            throw new FunctionException("OC-01-001-01-16-007");
        }
    }

    private static void checkOrderLineErrAndAddFailMsg(boolean checkTrue, OrderLine orderLine, SalesOrderAtomCreateResponse response) {
        if (checkTrue) {
            // 追加异常信息返回
            List<OrderLineAtomCreateResponse> orderDetails = Optional.ofNullable(response.getOrderDetails()).orElse(Lists.newArrayList());
            OrderLineAtomCreateResponse lineResponse = new OrderLineAtomCreateResponse();
            lineResponse.setSourceLineNum(orderLine.getSourceLineNum());
            //lineResponse.setProductCode(orderLine.getScItemId());
            lineResponse.setErrorCode("OC-01-001-01-16-008");
            lineResponse.setMessage("销售订单批量创建部分明细失败");
            orderDetails.add(lineResponse);

            response.setOrderDetails(orderDetails);
            response.setErrorCode("OC-01-001-01-16-008");
            response.setMessage("销售订单批量创建部分明细失败");
            // DB事务回滚
            throw new FunctionException("OC-01-001-01-16-007");
        }
    }

    private Order assembleSaveOrder(AtomOrderDO atomOrderDO) {
        Order order = atomOrderDO.getOrder();
//        // 当销售单号为空时，生产序列号
//        order.setOrderBizId(Optional.ofNullable(order.getOrderBizId())
//                .orElse(customSequenceAccessor.getNextStringSequence(APP_CODE, SEQ_CODE)));
        // 当订单标准为空时，默认【订单标签】为 normal

        // 默认【单据状态】为 待提交
        order.setStatus(Optional.ofNullable(order.getStatus()).orElse(OrderStatus.BEFORE_SUBMIT.getCode()));
        // 扩展信息打标
        order.setOrderTag(Optional.ofNullable(order.getOrderTag()).orElse(SetOrderTag.NORMAL));
        //获取序列编码
        order.setOrderBizId(createNextStringSequence(order));
        order.setFeatures(buildOrderFeatureStr(order));
        // 版本号初始化
        order.setSyncVersion(0);
        order.setGmtCreate(new Date());
        //order.setGmtModified(new Date());
        return order;
    }

    private String createNextStringSequence(Order order) {
        Map<String, String> orderTagOfSeqCode = Maps.newHashMap();
        orderTagOfSeqCode.put(SetOrderTag.NORMAL,   "saleOrderSequence");
        orderTagOfSeqCode.put(SetOrderTag.RETURN,   "returnOrderSequence");
        orderTagOfSeqCode.put(SetOrderTag.EXCHANGE, "exchangeOrderSequence");

        String seqCode = orderTagOfSeqCode.get(order.getOrderTag());
        if(StringUtils.isNotBlank(seqCode)) {
            return customSequenceAccessor.getNextStringSequence("cr_b2b_trade_center", seqCode);
        }
        return customSequenceAccessor.getNextStringSequence("cr_b2b_trade_center", "saleOrderSequence");
    }

    private String buildOrderFeatureStr(Order order) {
        Map<String, String> features = JSONObject.parseObject(order.getFeatures(), new TypeReference<Map<String, String>>() {
        });
        features = Optional.ofNullable(features).orElse(Maps.newHashMap());
        // 针对当前链路打标
        features.put("os", "OrderCenter");
        return JSONObject.toJSONString(features);
    }

    private static SalesOrderAtomCreateResponse successSaveOrder(AtomOrderDO atomOrderDO) {
        SalesOrderAtomCreateResponse response = new SalesOrderAtomCreateResponse();
        response.setSourceOrderNo(atomOrderDO.getOrder().getSourceOrderNo());
        response.setSalesOrderNo(atomOrderDO.getOrder().getOrderBizId());
        return response;
    }

    private static SalesOrderAtomCreateResponse failSaveOrder(AtomOrderDO atomOrderDO) {
        SalesOrderAtomCreateResponse response = new SalesOrderAtomCreateResponse();
        response.setSourceOrderNo(atomOrderDO.getOrder().getSourceOrderNo());
        response.setErrorCode("OC-01-001-01-16-007");
        response.setMessage("销售订单批量创建整单失败");
        return response;
    }

    private static void addFailDetailsResponse(SalesOrderAtomCreateResponse createResponse, String sourceLineNum, String productCode) {
        List<OrderLineAtomCreateResponse> orderDetails =
                Optional.ofNullable(createResponse.getOrderDetails()).orElse(Lists.newArrayList());
        OrderLineAtomCreateResponse lineResponse = new OrderLineAtomCreateResponse();
        lineResponse.setSourceLineNum(sourceLineNum);
        //lineResponse.setProductCode(productCode);
        lineResponse.setErrorCode("OC-01-001-01-16-008");
        lineResponse.setMessage("销售订单批量创建部分明细失败");
        orderDetails.add(lineResponse);
        createResponse.setOrderDetails(orderDetails);
        createResponse.setErrorCode("OC-01-001-01-16-008");
        createResponse.setMessage("销售订单批量创建部分明细失败");
    }

    private static void addSuccessDetailsResponse(SalesOrderAtomCreateResponse createResponse, String lineNum, String productCode, String sourceLineNum) {
        List<OrderLineAtomCreateResponse> orderDetails =
                Optional.ofNullable(createResponse.getOrderDetails()).orElse(Lists.newArrayList());
        createResponse.setOrderDetails(orderDetails);

        OrderLineAtomCreateResponse lineResponse = new OrderLineAtomCreateResponse();
        //lineResponse.setProductCode(productCode);
        lineResponse.setSourceLineNum(sourceLineNum);
        lineResponse.setLineNum(lineNum);

        orderDetails.add(lineResponse);
    }


    private static void setSuccessOrderResponse(SalesOrderAtomCreateResponse response, Order order) {
        response = new SalesOrderAtomCreateResponse();
        response.setSourceOrderNo(order.getSourceOrderNo());
        response.setSalesOrderNo(order.getOrderBizId());
    }

    private static void addSuccessDetailsResponse(SalesOrderAtomCreateResponse createResponse, OrderLine orderLine) {
        List<OrderLineAtomCreateResponse> orderDetails =
                Optional.ofNullable(createResponse.getOrderDetails()).orElse(Lists.newArrayList());
        createResponse.setOrderDetails(orderDetails);

        OrderLineAtomCreateResponse lineResponse = new OrderLineAtomCreateResponse();
        //lineResponse.setProductCode(orderLine.getScItemId());
        lineResponse.setSourceLineNum(orderLine.getSourceLineNum());
        lineResponse.setLineNum(orderLine.getSerialNumber());

        orderDetails.add(lineResponse);
    }
}
